﻿using DotNetty.Buffers;
using DotNetty.Codecs;
using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using System;
using System.Threading.Tasks;
using DotNetty.Handlers.Timeout;

namespace Coldairarrow.DotNettySocket
{
    class TcpSocketServerBuilder :
        BaseGenericServerBuilder<ITcpSocketServerBuilder, ITcpSocketServer, ITcpSocketConnection, byte[]>,
        ITcpSocketServerBuilder
    {
        private readonly int _readerIdleTimeSeconds;

        public TcpSocketServerBuilder(int port, int readerIdleTimeSeconds = 30)
            : base(port)
        {
            _readerIdleTimeSeconds = readerIdleTimeSeconds;
        }

        protected Action<IChannelPipeline> _setEncoder { get; set; }

        public ITcpSocketServerBuilder SetLengthFieldDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength, int lengthAdjustment, int initialBytesToStrip, ByteOrder byteOrder = ByteOrder.BigEndian)
        {
            _setEncoder += x => x.AddLast(new LengthFieldBasedFrameDecoder(byteOrder, maxFrameLength, lengthFieldOffset, lengthFieldLength, lengthAdjustment, initialBytesToStrip, true));

            return this;
        }

        public ITcpSocketServerBuilder SetLengthFieldEncoder(int lengthFieldLength)
        {
            _setEncoder += x => x.AddLast(new LengthFieldPrepender(lengthFieldLength));

            return this;
        }

        public async override Task<ITcpSocketServer> BuildAsync()
        {
            TcpSocketServer tcpServer = new TcpSocketServer(_port, _event);

            var serverChannel = await new ServerBootstrap()
                .Group(new MultithreadEventLoopGroup(), new MultithreadEventLoopGroup())
                .Channel<TcpServerSocketChannel>()
                .Option(ChannelOption.SoBacklog, 1024)
                .Option(ChannelOption.TcpNodelay, true)
                .ChildHandler(new ActionChannelInitializer<IChannel>(channel =>
                {
                    //IdleStateHandler心跳检测处理器，添加自定义处理Handler类实现userEventTriggered()方法作为超时事件的逻辑处理
                    //IdleStateHandler心跳检测每30秒进行一次读检测，如果十秒内ChannelRead()方法未被调用则触发一次userEventTrigger()方法.
                    IChannelPipeline pipeline = channel.Pipeline;
                    _setEncoder?.Invoke(pipeline);
                    pipeline.AddLast(new IdleStateHandler(_readerIdleTimeSeconds, 0, 0), new CommonChannelHandler(tcpServer));//第一个参数为读，第二个为写，第三个为读写全部

                    //IChannelPipeline pipeline = channel.Pipeline;
                    //_setEncoder?.Invoke(pipeline);
                    //pipeline.AddLast(new CommonChannelHandler(tcpServer));
                })).BindAsync(_port);
            _event.OnServerStarted?.Invoke(tcpServer);
            tcpServer.SetChannel(serverChannel);

            return await Task.FromResult(tcpServer);
        }
    }
}